package battleofthejavasea;
import java.applet.Applet;
import java.awt.*;
import com.sun.j3d.utils.universe.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.j3d.*;
import javax.swing.JOptionPane;
import javax.vecmath.*;


/**
 *
 * @author Murata, Saito, Santana
 */
public class BTJSGameFrame extends Applet {
    //Universo
    SimpleUniverse simpleUniverse;

    //Objeto c/ informações de posicionamento do barco e turno.
    public BTJSGameLogic btjsGameLogic = new BTJSGameLogic();

    //Verifica o fim do jogo.
    BTJS_DTOPlayerWinner btjsPW = new BTJS_DTOPlayerWinner();

    //Canvas
    Canvas3D c;

    public BTJSGameFrame (){
	}

    @Override
    public void init() {

            //código padrão do Java 3d para definir o layout
            setLayout(new BorderLayout());
            c = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
            //Centraliza o canvas no layout
            add("Center", c);
            simpleUniverse= new SimpleUniverse(c);

            //Cria os principais elementos e retorna como grafo de cena
            BranchGroup scene = new BranchGroup();
           
            try {
                createSceneGraph();
            } catch (FileNotFoundException ex) {
                Logger.getLogger(BTJSGameFrame.class.getName()).log(Level.SEVERE, null, ex);
            }

            //Alterna a visão da câmera
            TransformGroup transformGroupCamera = simpleUniverse.getViewingPlatform().getViewPlatformTransform();
            Transform3D transform3DCamera = new Transform3D();
            transform3DCamera.lookAt(new Point3d(0, 9.5, 18), new Point3d(0,4.20,0), new Vector3d(0,0,-1));
            transform3DCamera.invert();
            transformGroupCamera.setTransform(transform3DCamera);
            
            //Otimiza o programa
            scene.compile();

            //adiciona o grafo de cena no universo
            simpleUniverse.addBranchGraph(scene);

    }

    //Um dos principais métodos do sistema: posiciona todos os barcos para um determinado jogador
    public void addBoat() throws FileNotFoundException, UnknownHostException, IOException, ClassNotFoundException{
        //Objeto criador de navios
        BTJSShipCreator btjsShipCreator = new BTJSShipCreator();

        //Objeto "De->Para" para identificar linhas e colunas
        BTJSPositionInterpreter btjsPInt = new BTJSPositionInterpreter();

        //Posiciona os navios para o início do jogo.
        ArrayList<String> boatTypes = new ArrayList<String>();

        boatTypes.add("crusador.obj");
        boatTypes.add("submarine.obj");
        boatTypes.add("encouracado.obj");
        boatTypes.add("portaAviao.obj");

        //itera por todos os tipos de barco e configura-os na tela
        for(int i = 0; i < boatTypes.size();i++){
            String boatType = boatTypes.get(i);

            if(boatType.equals("crusador.obj")){
                JOptionPane.showMessageDialog(this, "Adicionando 4 Cruzadores: 2 células de comprimento");
                //4 Cruzadores
                for(int j = 0; j < 4; j++){
                    String rowValue = "";
                    int colValue = 0;

                    boolean validating = true;

                    float z = 0;
                    float x = 0;
                    boolean rotate = false;

                    while(validating){
                        rowValue = getStringInput(false);
                        colValue = getNumberInput(false);
                        
                        z = btjsPInt.getRowValue(rowValue);
                        x = btjsPInt.getColumnValue(colValue);
                        rotate = btjsPInt.setRotation(getStringYesNo());

                        if(btjsGameLogic.checkPosition("crusador", z, x, rowValue, colValue, rotate))
                            validating = false;
                        else
                            JOptionPane.showMessageDialog(this, "Posição inválida para o barco!");
                    }

                    simpleUniverse.addBranchGraph(btjsShipCreator.getShip("crusador.obj",x,0,z, rotate));
                    btjsGameLogic.addBoatCoordinates("crusador.obj", rowValue, colValue, rotate);

                }
            }
            else if(boatType.equals("submarine.obj")){
                JOptionPane.showMessageDialog(this, "Adicionando 2 Submarinos: 1 Célula comprimento");
                //2 Submarinos
                for(int j = 0; j < 2; j++){
                    String rowValue = "";
                    int colValue = 0;

                    boolean validating = true;

                    float z = 0;
                    float x = 0;

                    while(validating){
                        rowValue = getStringInput(false);
                        colValue = getNumberInput(false);
                        
                        z = btjsPInt.getRowValue(rowValue);
                        x = btjsPInt.getColumnValue(colValue);
                        
                        if(btjsGameLogic.checkPosition("submarine", z, x, rowValue,colValue, false))
                            validating = false;
                        else
                            JOptionPane.showMessageDialog(this, "Posição inválida para o barco!");
                    }

                    simpleUniverse.addBranchGraph(btjsShipCreator.getShip("submarine.obj",x,0,z, false));
                    btjsGameLogic.addBoatCoordinates("submarine.obj", rowValue, colValue, false);
                }
            }
            else if(boatType.equals("encouracado.obj")){
                JOptionPane.showMessageDialog(this, "Adicionando 4 Encouraçados: 3 células comprimento");
                //4 Encouraçados
                for(int j = 0; j < 4; j++){
                    String rowValue = "";
                    int colValue = 0;

                    boolean validating = true;

                    float z = 0;
                    float x = 0;
                    boolean rotate = false;

                    while(validating){
                        rowValue = getStringInput(false);
                        colValue = getNumberInput(false);

                        z = btjsPInt.getRowValue(rowValue);
                        x = btjsPInt.getColumnValue(colValue);
                        rotate = btjsPInt.setRotation(getStringYesNo());

                        if(btjsGameLogic.checkPosition("encouracado", z, x,rowValue,colValue, rotate))
                            validating = false;
                        else
                            JOptionPane.showMessageDialog(this, "Posição inválida para o barco!");

                    }
                        simpleUniverse.addBranchGraph(btjsShipCreator.getShip("encouracado.obj",x,0,z, rotate));
                        btjsGameLogic.addBoatCoordinates("encouracado.obj", rowValue, colValue, rotate);
                }
            }
            else if(boatType.equals("portaAviao.obj")){
                JOptionPane.showMessageDialog(this, "Adicionando 1 porta aviões: 4 células comprimento");
                //1 porta aviões

                String rowValue = "";
                int colValue = 0;

                boolean validating = true;

                float z = 0;
                float x = 0;
                boolean rotate = false;

                while(validating){
                    rowValue = getStringInput(false);
                    colValue = getNumberInput(false);

                    z = btjsPInt.getRowValue(rowValue);
                    x = btjsPInt.getColumnValue(colValue);
                    rotate = btjsPInt.setRotation(getStringYesNo());
                    
                    if(btjsGameLogic.checkPosition("portaaviao", z, x,rowValue, colValue, rotate))
                        validating = false;
                    else
                        JOptionPane.showMessageDialog(this, "Posição inválida para o barco!");
                }

                simpleUniverse.addBranchGraph(btjsShipCreator.getShip("portaAviao.obj",x,0,z, rotate));

                btjsGameLogic.addBoatCoordinates("portaAviao.obj", rowValue, colValue, rotate);
            }
        }
    }

    //Ativa sondas para espionar inimigo
    public void spyEnemy() throws FileNotFoundException{

        //Objeto "De->Para" para identificar linhas e colunas
        BTJSPositionInterpreter btjsPInt = new BTJSPositionInterpreter();

        //Objeto para printar o resultado da sonda
        BTJSGameSymbols btjsGS = new BTJSGameSymbols();

        boolean validating = true;

        String rowValue = "";
        int colValue = 0;

        float z = 0;
        float x = 0;

        while(validating){
            rowValue = getStringInput(true);
            colValue = getNumberInput(true);

            z = btjsPInt.getRowValue(rowValue);
            x = btjsPInt.getColumnValue(colValue);

            if(btjsGameLogic.checkSondaPosition(z,x)){
                validating = false;
            }
            else{
                JOptionPane.showMessageDialog(this, "Posição inválida para a sonda: Lembrando que a sonda varre uma área 3x3");
            }

        }
        //Revela área 3x3 a partir a posição inicial
         for(BTJS_DTOBoatUnitPosition pos : btjsGameLogic.getPlayer2BoatsCoords().getBoatPositions()) {
                if(pos != null){
                        if(pos.row.equals(rowValue) && pos.column == colValue)
                            simpleUniverse.addBranchGraph(btjsGS.sondaResult(btjsPInt.getRowValueShot(rowValue), btjsPInt.getColumnValue(colValue)));
                        else if(pos.row.equals(rowValue) && pos.column == colValue+1)
                            simpleUniverse.addBranchGraph(btjsGS.sondaResult(btjsPInt.getRowValueShot(rowValue), btjsPInt.getColumnValue(colValue+1)));
                        else if(pos.row.equals(rowValue) && pos.column == colValue+2)
                            simpleUniverse.addBranchGraph(btjsGS.sondaResult(btjsPInt.getRowValueShot(rowValue), btjsPInt.getColumnValue(colValue+2)));

                        else if(pos.row.equals(btjsGameLogic.fetchNextRow(rowValue)) && pos.column == colValue)
                            simpleUniverse.addBranchGraph(btjsGS.sondaResult(btjsPInt.getRowValueShot(btjsGameLogic.fetchNextRow(rowValue)), btjsPInt.getColumnValue(colValue)));
                        else if(pos.row.equals(btjsGameLogic.fetchNextRow(rowValue)) && pos.column == colValue+1)
                            simpleUniverse.addBranchGraph(btjsGS.sondaResult(btjsPInt.getRowValueShot(btjsGameLogic.fetchNextRow(rowValue)), btjsPInt.getColumnValue(colValue+1)));
                        else if(pos.row.equals(btjsGameLogic.fetchNextRow(rowValue)) && pos.column == colValue+2)
                            simpleUniverse.addBranchGraph(btjsGS.sondaResult(btjsPInt.getRowValueShot(btjsGameLogic.fetchNextRow(rowValue)), btjsPInt.getColumnValue(colValue+2)));

                        else if(pos.row.equals(btjsGameLogic.fetchNextRow(btjsGameLogic.fetchNextRow(rowValue))) && pos.column == colValue)
                            simpleUniverse.addBranchGraph(btjsGS.sondaResult(btjsPInt.getRowValueShot(btjsGameLogic.fetchNextRow(btjsGameLogic.fetchNextRow(rowValue))), btjsPInt.getColumnValue(colValue)));
                        else if(pos.row.equals(btjsGameLogic.fetchNextRow(btjsGameLogic.fetchNextRow(rowValue))) && pos.column == colValue+1)
                            simpleUniverse.addBranchGraph(btjsGS.sondaResult(btjsPInt.getRowValueShot(btjsGameLogic.fetchNextRow(btjsGameLogic.fetchNextRow(rowValue))), btjsPInt.getColumnValue(colValue+1)));
                        else if(pos.row.equals(btjsGameLogic.fetchNextRow(btjsGameLogic.fetchNextRow(rowValue))) && pos.column == colValue+2)
                            simpleUniverse.addBranchGraph(btjsGS.sondaResult(btjsPInt.getRowValueShot(btjsGameLogic.fetchNextRow(btjsGameLogic.fetchNextRow(rowValue))), btjsPInt.getColumnValue(colValue+2)));
                }
        }


    }

    //Começa o jogo.
    public void startShooting() throws FileNotFoundException{
        //Contador de tiros já disparados
        int shotsCount = 0;
        boolean gameEnded = false;

        if(!gameEnded){
            if(btjsGameLogic.getPlayer1BoatsCoords().getIsMyTurn()){
             while(!btjsGameLogic.checkGameEnd(btjsPW).getIsLocalPlayerWinner()
                     && !btjsGameLogic.checkGameEnd(btjsPW).getIsRemotePlayerWinner()
                     && shotsCount < 3 ){

                   boolean IsNewPosition = true;
                   String rowValue = "";
                   int colValue = 0;

                   while(IsNewPosition){

                   rowValue = getStringInput(true);
                   colValue = getNumberInput(true);
                   boolean validate = true;

                   //Verifica se posição já foi atingida
                    for(int i = 0; i < 26; i++){
                        if(btjsGameLogic.getPlayer1BoatsCoords().getEnemyShotPositions()[i] != null)
                            if(btjsGameLogic.getPlayer1BoatsCoords().getEnemyShotPositions()[i].row.equals(rowValue.toLowerCase()) && (btjsGameLogic.getPlayer1BoatsCoords().getEnemyShotPositions()[i].column == colValue))
                            {
                                    JOptionPane.showMessageDialog(this, "Você já atirou nesta posição!");
                                    validate = false;
                            }
                    }

                   if(validate)
                       IsNewPosition = false;

                   }

                   //objeto que efetua disparos e verifica erros/acertos.
                   btjsGameLogic.shootCoordinate(rowValue, colValue, simpleUniverse);
                   btjsPW = btjsGameLogic.checkGameEnd(btjsPW);
                 
                    shotsCount++;

                    //Verifica se o jogo acabou.
                    gameEnded = endGame();
                }
                //Passa a vez para o outro jogador
                btjsGameLogic.getPlayer1BoatsCoords().setIsMyTurn(false);
            }

            JOptionPane.showMessageDialog(this, "Aguarde o outro jogador efetuar os 3 disparos e pressione Iniciar Disparos!");
        }
    }

    public boolean endGame(){
            String victoryStatus = "";
            
            if(btjsPW.getIsLocalPlayerWinner()){
                victoryStatus = " Você perdeu! :(";
                int score = btjsPW.getLocalPlayerScore();
                btjsPW.setLocalPlayerScore(score);
                JOptionPane.showMessageDialog(this, "O jogo terminou!" + victoryStatus);
                return true;
            }
            else if(btjsPW.getIsRemotePlayerWinner()){
                victoryStatus = " Você venceu! :)";
                int score = btjsPW.getRemotePlayerScore();
                btjsPW.setRemotePlayerScore(score);
                JOptionPane.showMessageDialog(this, "O jogo terminou!" + victoryStatus);
                return true;
            }
            return false;
    }

    //Adiciona elementos importantes de cena, tais como luz, mar...
    public void createSceneGraph() throws FileNotFoundException {
	
        //Adiciona luzes
        BTJSLights btjsLights = new BTJSLights();
        simpleUniverse.addBranchGraph(btjsLights.getLights());

        //Adiciona o mar
        SeaObject seaObj = new SeaObject();
        simpleUniverse.addBranchGraph(seaObj.createSea());

        //Adiciona o mar para tiros (plano de tiros contra o outro jogador)
        SeaShots seaShotsObj = new SeaShots();
        simpleUniverse.addBranchGraph(seaShotsObj.createSea());

    }

    //Valida input de letras válidas.
    public String getStringInput(boolean shooting) {

        String letter = "";

        ArrayList<String> arrListChars = new ArrayList<String>();
        arrListChars.add("a");
        arrListChars.add("b");
        arrListChars.add("c");
        arrListChars.add("d");
        arrListChars.add("e");
        arrListChars.add("f");
        arrListChars.add("g");
        arrListChars.add("h");
        arrListChars.add("i");
        arrListChars.add("j");

        boolean IsInvalidLetter = true;

        while(IsInvalidLetter){

            if(!shooting) {
            letter = JOptionPane.showInputDialog(null, "Linha (Letra de A - J): ", "",1).toString();
            }
            else{
            letter = JOptionPane.showInputDialog(null, "Linha a atacar (Letra de A - J): ", "",1).toString();
            }

            if(arrListChars.contains(letter.toLowerCase()))   {
                IsInvalidLetter = false;
            }
            else {
                JOptionPane.showMessageDialog(this, "Entrada inválida!");
            }


        }
        return letter;
    }

    //Valida input para números válidos
    public Integer getNumberInput(boolean shooting) {

        int number = 0;

        ArrayList<Integer> arrListChars = new ArrayList<Integer>();

        arrListChars.add(1);
        arrListChars.add(2);
        arrListChars.add(3);
        arrListChars.add(4);
        arrListChars.add(5);
        arrListChars.add(6);
        arrListChars.add(7);
        arrListChars.add(8);
        arrListChars.add(9);
        arrListChars.add(10);

        boolean IsInvalidLetter = true;

        while(IsInvalidLetter){

            try
                {
                if(!shooting){
                number = Integer.parseInt(JOptionPane.showInputDialog(null, "Coluna (Número de 1 a 10) : ", "",1));
                }
                else{

                number = Integer.parseInt(JOptionPane.showInputDialog(null, "Coluna a atacar (Número de 1 a 10) : ", "",1));
                }

                if(arrListChars.contains(number)) {
                    IsInvalidLetter = false;
                }
                else {
                    JOptionPane.showMessageDialog(this, "Entrada inválida!");
                }
            }
            catch(Exception ex)
            {
                JOptionPane.showMessageDialog(this, "Entrada inválida!");
            }


        }
        return number;
    }


    public String getStringYesNo() {

        String letter = "";

        ArrayList<String> arrListChars = new ArrayList<String>();
        arrListChars.add("s");
        arrListChars.add("n");

        boolean IsInvalidLetter = true;

        while(IsInvalidLetter){

            letter = JOptionPane.showInputDialog(null, "Colocar barco na horizontal? (s ou n) : ", "",1);
            if(arrListChars.contains(letter.toLowerCase()))   {
                IsInvalidLetter = false;
            }
            else {
                JOptionPane.showMessageDialog(this, "Entrada inválida!");
            }


        }
        return letter;
    }

    //Função de limpeza após quitting
    @Override
    public void destroy() {	
	simpleUniverse.removeAllLocales();
    }
}
